package com.li.temperature.chart.service;

import java.util.ArrayList;
import java.util.List;

import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

import com.li.temperature.chart.R;
import com.li.temperature.chart.data.DataModel;
import com.li.temperature.chart.data.Stopwatch;
import com.li.temperature.chart.impl.IPhoneStatusResult;
import com.li.temperature.chart.util.AlertWakeLock;
import com.li.temperature.chart.util.ConfigA;
import com.li.temperature.chart.util.Constant;
import com.li.temperature.chart.view.CurveChartView;
import com.li.temperature.chart.view.TimeCountView;

public class PhoneStatusService extends Service implements IPhoneStatusResult {

    private static final String TAG = PhoneStatusService.class.getSimpleName();

    public static final int NOTICE_ID = 0x88;
    public static final String ACTION_START_MONITOR = "action_start_monitor";
    public static final String ACTION_STOP_MONITOR = "action_stop_monitor";

    public static final int STATUS_RUNNING = 0;
    public static final int STATUS_STOP = 2;

    public static boolean isRunning;

    private PhoneStatusManager mPhoneStatusManager;

    private WindowManager mWm;
    private WindowManager.LayoutParams mParams;
    private static final int MSG_SHOW_WINDOW = 1;
    private static final int MSG_HIDE_WINDOW = 2;
    private static final int MSG_UPDATE_RESULT = 3;

    Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case MSG_SHOW_WINDOW:
                if (mView != null) {
                    mView.setVisibility(View.VISIBLE);
                }
                break;
            case MSG_HIDE_WINDOW:
                if (mView != null) {
                    mView.setVisibility(View.GONE);
                }
                break;
            case MSG_UPDATE_RESULT:
                Bundle data = msg.getData();
                int step = data.getInt(ConfigA.KEY_PREDICT_STEP);
                float predict = data.getFloat(TYPE_PREDICT_VALUE);
                float real = data.getFloat(TYPE_REAL_VALUE);
                curver_chart_view.updateStep(step);
                updatePredictPeriod(step);
                addPredictDataLine(predict);
                addRealDataLine(real);
                break;
            default:
                break;
            }
        }
    };

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initFloatWindow();
        initValue();

        mPhoneStatusManager = PhoneStatusManager.getInstance(this);
        mPhoneStatusManager.setIPhoneStatusResult(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (null == intent) {
            return super.onStartCommand(intent, flags, startId);
        }

        String action = intent.getAction();
        if (ACTION_START_MONITOR.equals(action)) {

            isRunning = true;

            mPhoneStatusManager.startMonitor();

            AlertWakeLock.acquireCpuWakeLock(this);

            startForground();

            doStartTime();

            showFloatWindow();
        } else if (ACTION_STOP_MONITOR.equals(action)) {

            isRunning = false;

            mPhoneStatusManager.stopMonitor();

            AlertWakeLock.releaseCpuLock();

            stopForground();

            doStopTime();

            clearData();

            hideFloatWindow();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private void startForground() {
        Log.d(Constant.TAG, "startForground");

        Notification.Builder nb = new Notification.Builder(this);
        nb.setWhen(System.currentTimeMillis());
        nb.setSmallIcon(R.drawable.ic_launcher);
        nb.setContentTitle(getString(R.string.app_name));
        nb.setContentText(getString(R.string.notification_content));
        nb.setPriority(Notification.PRIORITY_HIGH);
        startForeground(NOTICE_ID, nb.build());
    }

    private void stopForground() {
        Log.d(Constant.TAG, "stopForground");

        stopForeground(true);
    }

    private final static String TYPE_REAL_VALUE = "T14";
    private final static String TYPE_PREDICT_VALUE = "Y1";

    private View mView;
    private TimeCountView mTime;
    // 20 秒后
    private int predictStep = 20;
    private int predictPeriod = predictStep / CurveChartView.X_UINIT;

    private List<Float> realDatas;
    private List<Float> realDataSource;

    private List<Float> predictDatas;
    private List<Float> predictDatasSource;
    private CurveChartView curver_chart_view;

    private void initFloatWindow() {

        if (mView == null) {
            mWm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

            mView = LayoutInflater.from(this).inflate(R.layout.float_window, null);
            mTime = (TimeCountView) mView.findViewById(R.id.countview);
            curver_chart_view = (CurveChartView) mView.findViewById(R.id.curver_chart_view);

            mView.setOnTouchListener(new View.OnTouchListener() {
                int lastX = 0;
                int lastY = 0;
                int paramX = 0;
                int paramY = 0;

                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    switch (motionEvent.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        lastX = (int) motionEvent.getRawX();
                        lastY = (int) motionEvent.getRawY();
                        paramX = mParams.x;
                        paramY = mParams.y;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int dx = (int) motionEvent.getRawX() - lastX;
                        int dy = (int) motionEvent.getRawY() - lastY;
                        mParams.x = paramX + dx;
                        mParams.y = paramY + dy;
                        mWm.updateViewLayout(mView, mParams);
                        break;
                    }
                    return true;
                }
            });

            mView.setVisibility(View.GONE);
            mView.setBackgroundColor(0x80000000);
            mParams = new WindowManager.LayoutParams();
            mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
            mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
            mParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
            mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            mParams.format = PixelFormat.TRANSPARENT;

            mWm.addView(mView, mParams);
        }
    }

    private void showFloatWindow() {
        handler.sendEmptyMessage(MSG_SHOW_WINDOW);
    }

    private void hideFloatWindow() {
        handler.sendEmptyMessage(MSG_HIDE_WINDOW);
    }

    private void doStartTime() {
        DataModel.getDataModel().startStopwatch();
        startUpdatingTime();
        mTime.update();
    }

    private void doStopTime() {
        DataModel.getDataModel().resetStopwatch();
        stopUpdatingTime();
    }

    private void startUpdatingTime() {
        stopUpdatingTime();
        mTime.post(mTimeUpdateRunnable);
    }

    private void stopUpdatingTime() {
        mTime.removeCallbacks(mTimeUpdateRunnable);
    }

    private Stopwatch getStopwatch() {
        return DataModel.getDataModel().getStopwatch();
    }

    private final Runnable mTimeUpdateRunnable = new TimeUpdateRunnable();

    private final class TimeUpdateRunnable implements Runnable {
        @Override
        public void run() {
            if (getStopwatch().isRunning()) {
                final int period = 999;

                mTime.postDelayed(this, period);
                Log.d("suhuazhi", "Time period = " + period);
                if (null != mPhoneStatusManager) {
                    mPhoneStatusManager.updateMonitor();
                }
            }
        }
    }

    @Override
    public void updateResult(int type, double y, double t) {
        Message msg = new Message();
        msg.what = MSG_UPDATE_RESULT;
        Bundle data = new Bundle();
        data.putInt(ConfigA.KEY_PREDICT_STEP, type);
        data.putFloat(TYPE_REAL_VALUE, (float) t);
        data.putFloat(TYPE_PREDICT_VALUE, (float) y);
        msg.setData(data);
        handler.sendMessage(msg);
    }

    private void initValue() {
        realDatas = new ArrayList<Float>();
        realDataSource = new ArrayList<Float>();

        predictDatas = new ArrayList<Float>();
        predictDatasSource = new ArrayList<Float>();

        curver_chart_view.updateStep(predictStep);
        reset();
    }

    private void reset() {
        if (realDataSource != null) {
            realDataSource.clear();
        }

        if (realDatas != null) {
            realDatas.clear();
        }
        for (int i = 0; i < CurveChartView.X_SIZE; i++) {
            realDatas.add((float) CurveChartView.Y_START);
        }

        if (predictDatasSource != null) {
            predictDatasSource.clear();
        }

        if (predictDatas != null) {
            predictDatas.clear();
        }
        for (int i = 0; i < CurveChartView.X_SIZE; i++) {
            predictDatas.add((float) CurveChartView.Y_START);
        }
    }

    private void clearData() {
        reset();
        curver_chart_view.clearData();
    }

    private void addRealDataLine(float value) {
        Log.d(TAG, "X_START = " + CurveChartView.X_START);
        int size = realDataSource.size();
        if (size > CurveChartView.X_START) {
            realDataSource.remove(0);
        }

        realDataSource.add(value);

        int j = 0;
        for (int i = realDataSource.size() - 1; i >= 0; i--) {
            int index = CurveChartView.X_START - j;
            j++;
            realDatas.set(index, realDataSource.get(i));
            //Log.d(TAG, "realDatas:" + i + ", index = " + index + ", value = " + realDataSource.get(i));
        }

        curver_chart_view.updateReal(value);
        curver_chart_view.updateRealData(realDatas);
    }

    private void addPredictDataLine(float value) {
        int size = predictDatasSource.size();
        final int PREDICT_START_X = CurveChartView.X_START + predictPeriod;
        if (size > PREDICT_START_X) {
            predictDatasSource.remove(0);
        }
        predictDatasSource.add(value);

        int j = 0;
        for (int i = predictDatasSource.size() - 1; i >= 0; i--) {
            int index = PREDICT_START_X - j;
            j++;
            predictDatas.set(index, predictDatasSource.get(i));
            //Log.d(TAG, "predictData:" + i + ", index = " + index + ", value = " + predictDatasSource.get(i));
        }

        curver_chart_view.updatepPredict(value);
        curver_chart_view.updatePredictData(predictDatas);
    }

    private void updatePredictPeriod(int predictStep) {
        predictPeriod = predictStep / CurveChartView.X_UINIT;
    }
}
